/*
 * Copyright (C) 2013 'Chaos'.Personal
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.silly.adapter.reflect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.silly.adapter.utils.RLog;

/**
 * 通用的反射方法
 * 
 * @author Chaos
 * @date 2013-5-30
 */
public class ReflectUtils {

	/**
	 * 产生一个非Class的Object(silent mode)
	 * 
	 * @param target
	 * @return object
	 */
	public static Object newObjectSilent(Object target) {
		// step.1: 如果目标并非Class，直接返回即可
		if (!(target instanceof Class<?>)) {
			return target;
		}
		// step.2: 如果目标是Class，试图newInstance返回
		Object obj = null;

		try {
			obj = ((Class<?>) target).newInstance();
		} catch (InstantiationException e) {
			RLog.E.p("newObjectSlient Error ->", e);
		} catch (IllegalAccessException e) {
			RLog.E.p("newObjectSlient Error ->", e);
		}

		return obj;
	}

	/**
	 * 找到某个方法
	 * 
	 * @param methods
	 * @param name
	 * @return
	 */
	public static Method findMethodByName(Method[] methods, String name) {
		for (Method method : methods) {
			if (name.equalsIgnoreCase(method.getName())) {
				return method;
			}
		}
		return null;
	}

	public static Object getValue(Object entity, String fieldName) {
		try {
			Field field = entity.getClass().getDeclaredField(fieldName);
			return getValue(entity, field);
		} catch (NoSuchFieldException e) {
			throw new RuntimeException("NoSuchFieldException");
		}
	}

	/**
	 * 获取到对应的值(仅限于pojo)
	 * 
	 * @param entity
	 *            赋值对象
	 * @param field
	 *            pojo中对应的field
	 */
	public static Object getValue(Object entity, Field field) {

		if (entity == null || field == null) {
			return null;
		}
        
		Object value = null;
		try {
            field.setAccessible(true);
			value = field.get(entity);
		} catch (IllegalArgumentException e) {
			RLog.E.p("getValue error..." + e.toString());
		} catch (IllegalAccessException e) {
		    RLog.E.p("getValue error..." + e.toString());
		}
        
		return value;
	}

	public static boolean isImplements(Class<?> source, Class<?> _interface) {
		if (!_interface.isInterface()) {
			throw new IllegalArgumentException("you must set 'interface'");
		}

		return _interface.isAssignableFrom(source);
	}

	@SuppressWarnings("unchecked")
	public static Map<Object, Object> buildMap(Class<?> source) {
		Object map = newObjectSilent(source);
		if (map == null) {
			map = new HashMap<Object, Object>();
		}
		return (Map<Object, Object>) map;
	}

	@SuppressWarnings("unchecked")
	public static List<Object> buildList(Class<?> source) {
		Object list = newObjectSilent(source);
		if (list == null) {
			list = new ArrayList<Object>();
		}
		return (List<Object>) list;
	}

	@SuppressWarnings("unchecked")
	public static Set<Object> buildSet(Class<?> source) {
		Object set = newObjectSilent(source);
		if (set == null) {
			set = new HashSet<Object>();
		}
		return (Set<Object>) set;
	}

	public static Class<?>[] getGeneric(Class<?> clz, String name) {
		try {
			Field field = clz.getDeclaredField(name);
			return getGeneric(field);
		} catch (NoSuchFieldException e) {
			throw new RuntimeException("NoSuchFieldException");
		}
	}

	public static Class<?>[] getGeneric(Field field) {
		Type type = field.getGenericType();
		if (ParameterizedType.class.isAssignableFrom(type.getClass())) {
			// 拥有泛型
			Type[] types = ((ParameterizedType) type).getActualTypeArguments();
			Class<?>[] clazzs = new Class[types.length];
			for (int i = 0; i < types.length; i++) {
				try {
					RLog.D.p("the generic class is " + types[i].toString() + "try to findIt");
					clazzs[i] = Class.forName(types[i].toString());
				} catch (ClassNotFoundException e) {
					throw new RuntimeException(e);
				}
			}
			return clazzs;
		} else {
			return null;
		}
	}

	public static String[] getGenericStr(Field field) {
		Type type = field.getGenericType();
		if (ParameterizedType.class.isAssignableFrom(type.getClass())) {
			// 拥有泛型
			Type[] types = ((ParameterizedType) type).getActualTypeArguments();
			String[] str = new String[types.length];
			for (int i = 0; i < types.length; i++) {
				RLog.D.p("the generic str is >" + types[i].toString() + "<");
				str[i] = types[i].toString();
			}
			return str;
		} else {
			return null;
		}
	}

	public static String[] getGenericStr(Class<?> clz, String name) {
		try {
			Field field = clz.getDeclaredField(name);
			return getGenericStr(field);
		} catch (NoSuchFieldException e) {
			throw new RuntimeException("NoSuchFieldException");
		}
	}

	public static Class<?> getClassSliently(String name) {
		try {
			return Class.forName(name);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("ClassNotFoundException" + name);
		}
	}

	/**
	 * 得到真正的Class
	 * 
	 * @param obj
	 * @return
	 */
	public static Class<?> getAbsoluteClass(Object obj) {
		if (obj instanceof Class) {
			return (Class<?>) obj;
		} else {
			return obj.getClass();
		}
	}
    
	public static <T extends Annotation> T getAnnotation(Class<T> annotation, Object attached) {
		return getAnnotation(annotation, attached, null);
	}

	public static <T extends Annotation> T getAnnotation(Class<T> annotation, Object attached, Object description) {

		if (attached == null || annotation == null) {
            RLog.E.p("attached or annotation is null...");
			return null;
		}

		if (description == null) {
			// 返回attached的Class
			return attached.getClass().getAnnotation(annotation);
		} else if (description instanceof String) {
			String des = (String) description;
			try {
				Field field = attached.getClass().getDeclaredField(des);
				return field.getAnnotation(annotation);
			} catch (NoSuchFieldException e) {
				// do nothing...
				RLog.E.p("getAnnotation -> noSuchFieldException");
				return null;
			}
		} else if (description instanceof Field) {
			return ((Field) description).getAnnotation(annotation);
		} else{
			RLog.E.p("getAnnotation is unknown type " + description.getClass().getSimpleName());
			return null;
		}

	}

}
